#include "stdafx.h"
#include "_XContiguousBlock.h"
#include "IPALDebuggingServices.h"




_XContiguousBlock::_XContiguousBlock()
{

}

_XContiguousBlock::~_XContiguousBlock()
{
	XUINT32 dummy = 0;

	this->Cleanup(dummy);

	XASSERT(dummy == NULL);
}

void _XContiguousBlock::Cleanup( XUINT32 & outLeakedItems )
{
	XUINT32 uFoundFreeItems;

	outLeakedItems = 0;
	uFoundFreeItems = 0;

	while ( this->m_pHead )
	{
		++uFoundFreeItems;
		this->m_pHead = this->NextHead();
	}

	XASSERT(m_uNumberOfSlots >= uFoundFreeItems);

	outLeakedItems = this->m_uNumberOfSlots - uFoundFreeItems;

	delete [] this->m_pBlock;
	this->m_pBlock = NULL;
	this->m_pHead = NULL;
	this->m_uNumberOfSlots = 0;
	this->m_uItemSize = 0;
}

HRESULT _XContiguousBlock::Initialize( XUINT32 uItemSize, XUINT32 uNumberOfSlots )
{
	XRESULT hr = S_OK;
	XUINT32 * pBufferPtr = NULL;


	XINT64 cBufferSize = uNumberOfSlots * (uItemSize + sizeof(XUINT32));


	if ( uNumberOfSlots && cBufferSize <= XUINT32_MAX )
	{

		XASSERT_NOTNULL_WITH_HR(m_pBlock = new XUINT8[static_cast<XUINT32>(cBufferSize)],0x8007000Eu);

		for (XUINT32 i = 0; i < (XUINT32)cBufferSize; ++i )
			this->m_pBlock[i] = 0xCDu;

		XASSERT(uNumberOfSlots > 0);

		for (XUINT32 j = 0; j < uNumberOfSlots - 1; ++j )
		{
			pBufferPtr = (XUINT32 *)&this->m_pBlock[j * (uItemSize + sizeof(XUINT32))];
			*pBufferPtr = *(pBufferPtr + uItemSize + sizeof(XUINT32));
		}
		pBufferPtr = (XUINT32 *)&this->m_pBlock[(uItemSize + 4) * (uNumberOfSlots - 1)];

		*(XUINT32 *)pBufferPtr = NULL;

		this->m_pHead = this->m_pBlock;
		this->m_uNumberOfSlots = uNumberOfSlots;
		this->m_uItemSize = uItemSize;

	}
	else
	{
		XASSERT_SUCCESSED(E_UNEXPECTED);
	}
	return hr;
}

XUINT8 * _XContiguousBlock::Allocate()
{
	void *pBuffer = NULL;
	if ( this->m_pHead )
	{
		pBuffer = this->m_pHead + sizeof(XUINT32);
		this->m_pHead = this->NextHead();

		for ( XUINT32 i = 0; i < this->m_uItemSize; i++ )
		{
			XASSERT(((XUINT8 *)pBuffer)[i] == 0xcd);
		}
	}
	return (XUINT8 *)pBuffer;
}

HRESULT _XContiguousBlock::Release( XUINT8 * pBufferToFree )
{
	XRESULT result;
	unsigned int i;

	if ( pBufferToFree )
	{
		if (pBufferToFree >= this->m_pBlock
			&& (XUINT8 *)pBufferToFree <= &this->m_pBlock[this->m_uNumberOfSlots * (this->m_uItemSize + sizeof(XUINT32))] )
		{
			auto pNextPtr = ((XUINT8 *)pBufferToFree - sizeof(XUINT32));
			*pNextPtr = *(XUINT32*)this->m_pHead;
			this->m_pHead = pBufferToFree - sizeof(XUINT32);
			for ( i = 0; i < this->m_uItemSize; ++i )
				pBufferToFree[i] = 0xCDu;
			result = S_OK;
		}
		else
		{
			result = S_FALSE;
		}
	}
	else
	{
		result = S_OK;
	}
	return result;
}

XUINT8 * _XContiguousBlock::NextHead()
{
	return ((_XContiguousBlock *)m_pHead)->m_pBlock;
}

static_assert(sizeof(_XContiguousBlock) == 16,"!sizeof(_XContiguousBlock) == 16");
